#include "properties.h"
#include "common.h"
#include <codecvt>
#include <fstream>
#include <locale>

bool loaded = false;

Properties::Properties(void) : common(Common::getInstance()) { loaded = false; }

Properties::~Properties(void) {}

Properties &Properties::getInstance() {
    static Properties instance;
    instance.load();
    return instance;
}

// void Properties::setupDefaults() {
//     // exe.javaHome=jre;${JAVA_HOME}
//     // exe.vmOptions=-Dfile.encoding=UTF-8
//     // exe.classPath=jstart.jar
//     // exe.mainClass=jstart/exe/Main
//     // exe.mainArgs=--launch
//     map[L"exe.javaHome"] = {common.getExeDir() + L"\\jre", common.getEnvVar(L"JAVA_HOME")};
//     map[L"exe.vmOptions"] = {L"-Dfile.encoding=UTF-8"};
//     map[L"exe.classPath"] = {common.getExeDir() + L"\\jstart.jar"};
//     map[L"exe.mainArgs"] = {L"--launch"};
// }

bool Properties::expandPath(WString &value) {
    if (value.empty()) {
        return false;
    }

    if (value.find(L":") != value.npos) { // 绝对路径
        return true;
    }

    if (value.find(L"${EXE_DIR}") == 0) {
        value = common.getExeDir() + value.substr(10);
    } else if (value.find(L"${JAVA_HOME}") == 0) {
        value = common.getEnvVar(L"JAVA_HOME") + value.substr(12);
    } else {
        value = common.getExeDir() + L"\\" + value;
    }
    return true;
}

void Properties::load() {
    if (loaded) {
        return;
    }

    WString filename = common.getExeDir() + L"\\jstart.properties";
    if (!common.isFileExists(filename)) {
        loaded = true;
        return;
    }

    // 读取配置文件
    std::wifstream stream(filename.data());
    const std::locale emptyLocale = std::locale::empty();
    const std::locale utf8Locale = std::locale(emptyLocale, new std::codecvt_utf8<wchar_t>());
    stream.imbue(utf8Locale);
    if (stream.is_open()) {
        WString key;
        while (!stream.eof()) {
            WString line;
            std::getline(stream, line);
            if (line.empty() || line[0] == '#') { // 跳过空行和注释行
                continue;
            }
            size_t eq = line.find('=');
            if (eq == line.npos) {
                throw std::runtime_error("Invalid config item: \n" + std::string(line.begin(), line.end()));
            }
            key = line.substr(0, eq);
            std::list<WString> values;
            if (line.find(L"exe.mainClass") == 0) {
                WString value = common.trimString(line.substr(eq + 1));
                if (!value.empty()) {
                    map[key] = {value};
                }
            } else if (line.find(L"exe.mainArgs") == 0) {
                for (WString value : common.splitString(common.trimString(line.substr(eq + 1)), ' ')) {
                    if (!value.empty()) {
                        values.push_back(value);
                    }
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else if (line.find(L"exe.javaHome") == 0 || line.find(L"exe.classPath") == 0) {
                for (WString value : common.splitString(common.trimString(line.substr(eq + 1)), ';')) {
                    if (expandPath(value)) {
                        values.push_back(value);
                    }
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else if (line.find(L"exe.") == 0) {
                for (WString value : common.splitString(common.trimString(line.substr(eq + 1)), ';')) {
                    values.push_back(value);
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else {
                break;
            }
        }
    }
    loaded = true;
}

std::list<WString> Properties::getJavaHome() {
    if (map.count(L"exe.javaHome") == 1) {
        return map[L"exe.javaHome"];
    }
    std::list<WString> javaHome = {common.getExeDir() + L"\\jre", common.getEnvVar(L"JAVA_HOME")};
    return javaHome;
}

std::list<WString> Properties::getVmOptions() { return map[L"exe.vmOptions"]; }

WString Properties::getClassPath() {
    WString fullClassPath;
    for (WString path : map[L"exe.classPath"]) {
        fullClassPath = path + L";";
    }
    return fullClassPath.empty() ? L"" : fullClassPath;
}

WString Properties::getMainClass() {
    if (map.count(L"exe.mainClass") == 1) {
        return map[L"exe.mainClass"].front();
    }
    return L"jstart/exe/Main";
}

std::list<WString> Properties::getMainArgs() {
    std::list<WString> args = common.getCommandLineArgs();
    return args.empty() ? map[L"exe.mainArgs"] : args;
}